﻿using System;
using System.Linq;
using UltimateHealer.Dynamics;
using UltimateHealer.Helpers;
using UltimateHealer.Managers;
using UltimateHealer.Settings;
using Styx;
using Styx.Combat.CombatRoutine;
using Styx.Logic;
using Styx.Logic.Combat;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using TreeSharp;
using Action = TreeSharp.Action;

namespace UltimateHealer.ClassSpecific.Paladin
{
    public static class Holy
    {
        [Class(WoWClass.Paladin)]
        [Spec(TalentSpec.HolyPaladin)]
        [Behavior(BehaviorType.Rest)]
        [Context(WoWContext.All)]
        public static Composite CreateHolyPaladinRest()
        {
            return new PrioritySelector(
                // Heal self before resting. There is no need to eat while we have 100% mana
                CreatePaladinHealBehavior(true),
                // Rest up damnit! Do this first, so we make sure we're fully rested.
                Rest.CreateDefaultRestBehaviour(),
                // Can we res people?
                Spell.Resurrect("Redemption"),
                // Make sure we're healing OOC too!
                CreateHolyPaladinActualHealing(false, false));
        }

        [Class(WoWClass.Paladin)]
        [Spec(TalentSpec.HolyPaladin)]
        [Behavior(BehaviorType.Heal)]
        [Context(WoWContext.Normal)]
        public static Composite CreateHolyPaladinNormalHealBehavior()
        {
            return
                new PrioritySelector(CreatePaladinHealBehavior());        }

        [Class(WoWClass.Paladin)]
        [Spec(TalentSpec.HolyPaladin)]
        [Behavior(BehaviorType.Heal)]
        [Context(WoWContext.Battlegrounds)]
        public static Composite CreateHolyPaladinBattlegroundHealBehavior()
        {
            return
                new PrioritySelector(CreatePaladinHealBehavior());
        }

        [Class(WoWClass.Paladin)]
        [Spec(TalentSpec.HolyPaladin)]
        [Behavior(BehaviorType.Heal)]
        [Context(WoWContext.Instances)]
        public static Composite CreateHolyPaladinBattlegroundInstancesBehavior()
        {
            return
                new PrioritySelector(CreatePaladinHealBehavior());
        }

        [Class(WoWClass.Paladin)]
        [Spec(TalentSpec.HolyPaladin)]
        [Behavior(BehaviorType.CombatBuffs)]
        [Context(WoWContext.All)]
        public static Composite CreateHolyPaladinCombatBuffsBehavior()
        {
            return
                new PrioritySelector(
                    Spell.BuffSelf(
                        "Divine Plea",
                        ret => StyxWoW.Me.ManaPercent <= UltimateHealerSettings.Instance.Paladin.DivinePleaMana)
                    );
        }

        private static bool _holyPaladinCombatNeeded
        {
            get
            {
                if (Battlegrounds.IsInsideBattleground && StyxWoW.Me.HealthPercent < 50 && HealerManager.Instance.FirstUnit == null)
                {
                    return true;
                }
                if (!StyxWoW.Me.IsInParty && !StyxWoW.Me.IsInRaid)
                {
                    return true;
                }
                return false;
            }
        }

        [Class(WoWClass.Paladin)]
        [Spec(TalentSpec.HolyPaladin)]
        [Behavior(BehaviorType.Combat)]
        [Context(WoWContext.All)]
        public static Composite CreateHolyPaladinCombatBehavior()
        {
            return
                new PrioritySelector(
                    Safers.EnsureTarget(),
                    Spell.Buff("Judgement", 
                                ret => SpellManager.HasSpell("Judgement") &&
                                       !StyxWoW.Me.HasAura("Judgements of the Pure") &&
                                       StyxWoW.Me.CurrentTarget.Distance <= SpellManager.Spells["Judgement"].MaxRange - 2 &&
                                       StyxWoW.Me.CurrentTarget.InLineOfSpellSight &&
                                       StyxWoW.Me.IsSafelyFacing(StyxWoW.Me.CurrentTarget) &&
                                       UltimateHealerSettings.Instance.Paladin.wannaJudge),
                    new Decorator(
                        ret => Battlegrounds.IsInsideBattleground || (!StyxWoW.Me.IsInParty && !StyxWoW.Me.IsInRaid),
                        new PrioritySelector(
                            Movement.CreateMoveToLosBehavior(),
                            Movement.CreateFaceTargetBehavior(),
                            Helpers.Common.CreateAutoAttack(true),
                            Helpers.Common.CreateInterruptSpellCast(ret => StyxWoW.Me.CurrentTarget),
                            Spell.Buff("Judgement", ret =>  UltimateHealerSettings.Instance.Paladin.wannaJudge),
                            Spell.Cast("Hammer of Wrath", ret => UltimateHealerSettings.Instance.Paladin.wannaHammerofWrath),
                            Spell.Cast("Crusader Strike", ret => UltimateHealerSettings.Instance.Paladin.wannaCrusaderStrike),
                            Spell.Cast("Exorcism", ret => UltimateHealerSettings.Instance.Paladin.wannaExorcism),
                            Spell.Cast("Holy Wrath", ret => UltimateHealerSettings.Instance.Paladin.wannaHolyWrath),
                            Spell.Cast("Consecration", ret => UltimateHealerSettings.Instance.Paladin.wannaConsecration),
                            Movement.CreateMoveToTargetBehavior(true, 5f)
                            ))
                    );
        }

        [Class(WoWClass.Paladin)]
        [Spec(TalentSpec.HolyPaladin)]
        [Behavior(BehaviorType.Pull)]
        [Context(WoWContext.All)]
        public static Composite CreateHolyPaladinPullBehavior()
        {
            return new PrioritySelector(
                new Decorator(
                    ret => !StyxWoW.Me.IsInParty && !StyxWoW.Me.IsInRaid,
                    new PrioritySelector(
                        Movement.CreateMoveToLosBehavior(),
                        Movement.CreateFaceTargetBehavior(),
                        Spell.Cast("Judgement"),
                        Helpers.Common.CreateAutoAttack(true),
                        Movement.CreateMoveToTargetBehavior(true, 5f)
                        ))
                );
        }
      
        internal static Composite CreatePaladinHealBehavior()
        {
            return CreateHolyPaladinActualHealing(false, true);
        }

        internal static Composite CreatePaladinHealBehavior(bool selfOnly)
        {
            return CreateHolyPaladinActualHealing(selfOnly, false);
        }

        internal static Composite CreateHolyPaladinActualHealing(bool selfOnly, bool moveInRange)
        {
            HealerManager.NeedHealTargeting = true;
            return
                   new PrioritySelector(
                       ctx => selfOnly ? StyxWoW.Me : HealerManager.Instance.FirstUnit,
                       new Decorator(
                       ret => ret != null && (moveInRange || ((WoWUnit)ret).InLineOfSpellSight && ((WoWUnit)ret).DistanceSqr < 40 * 40),
                           new PrioritySelector(
                               Spell.WaitForCast(),
                               new Decorator(ret => moveInRange, Movement.CreateMoveToLosBehavior(ret => (WoWUnit)ret)),
                               // if we have FocusedUnit -> Beacon FocusedUnit (if this is set in Settings)
                               Spell.Buff("Beacon of Light", ret => StyxWoW.Me.FocusedUnit, ret => ret is WoWPlayer && !((WoWPlayer)ret).HasMyAura("Beacon of Light") && UltimateHealerSettings.Instance.ImportTankFromFocus == GetTank.fromFocus),
                               // If we are in a Raid and noone has Beacon -> Beacon A tank
                               Spell.Buff("Beacon of Light",ret => (WoWUnit)ret, ret => ret is WoWPlayer && Group.Tanks.Contains((WoWPlayer)ret) && Group.Tanks.All(t => !t.HasMyAura("Beacon of Light")) && UltimateHealerSettings.Instance.ImportTankFromFocus == GetTank.standard),
                               // Oh shit / Emergency
                               Spell.Heal("Lay on Hands", ret => (WoWUnit)ret, ret => StyxWoW.Me.Combat && !((WoWUnit)ret).HasAura("Forbearance") && ((WoWUnit)ret).HealthPercent <= UltimateHealerSettings.Instance.Paladin.minLayonHands),
                               // Cleanse - tbd
                               Spell.Buff("Hand of Protection", ret => ret is WoWPlayer && ((WoWUnit)ret).HealthPercent < UltimateHealerSettings.Instance.Paladin.minHandofProtection && !Group.Tanks.Contains((WoWPlayer)ret) && ((WoWUnit)ret).Distance < 30 && ((WoWUnit)ret).InLineOfSight && (StyxWoW.Me.Combat || ((WoWUnit)ret).Combat)),
                               Spell.Buff("Hand of Sacrifice",ret => StyxWoW.Me.FocusedUnit,ret => ret is WoWPlayer && ((WoWPlayer)ret).HealthPercent <= UltimateHealerSettings.Instance.Paladin.minHandofSacrifice && !((WoWPlayer)ret).IsMe && !((WoWPlayer)ret).Dead && !((WoWPlayer)ret).IsGhost),                               
                               Spell.BuffSelf("Divine Protection",ret => StyxWoW.Me.HealthPercent <= UltimateHealerSettings.Instance.Paladin.minDivineProtection),
                               Spell.BuffSelf("Divine Plea",ret => StyxWoW.Me.ManaPercent <= UltimateHealerSettings.Instance.Paladin.DivinePleaMana && StyxWoW.Me.HealthPercent > 85),
                               Spell.BuffSelf("Divine Favor",ret => (!StyxWoW.Me.HasAura("Guardian of Ancient Kings") && !StyxWoW.Me.HasAura("Avenging Wrath") && !StyxWoW.Me.HasAura("Divine Plea")) && Unit.NearbyFriendlyPlayers.Count(u => !u.Dead && !u.IsGhost && u.Distance < 40 && u.HealthPercent < UltimateHealerSettings.Instance.Paladin.DivineFavorHealth) >= UltimateHealerSettings.Instance.Paladin.DivineFavorMembers),
                               Spell.BuffSelf("Avenging Wrath",ret => (!StyxWoW.Me.HasAura("Guardian of Ancient Kings") && !StyxWoW.Me.HasAura("Divine Favor") && !StyxWoW.Me.HasAura("Divine Plea")) && Unit.NearbyFriendlyPlayers.Count(u => !u.Dead && !u.IsGhost && u.Distance < 40 && u.HealthPercent < UltimateHealerSettings.Instance.Paladin.AvengingWrathHealth) >= UltimateHealerSettings.Instance.Paladin.AvengingWrathMembers),
                               Spell.Buff("Guardian of Ancient Kings", ret => ((!StyxWoW.Me.HasAura("Avenging Wrath") && !StyxWoW.Me.HasAura("Divine Favor") && !StyxWoW.Me.HasAura("Divine Plea"))) && Unit.NearbyFriendlyPlayers.Count(u => !u.Dead && !u.IsGhost && u.Distance < 40 && u.HealthPercent < UltimateHealerSettings.Instance.Paladin.GuardianoftheAncientKingsHealth) >= UltimateHealerSettings.Instance.Paladin.GuardianoftheAncientKingsMembers),
                               // Healing
                               Spell.Heal("Light of Dawn", ret => StyxWoW.Me, ret => StyxWoW.Me.CurrentHolyPower == 3 && Clusters.GetClusterCount((WoWPlayer)ret, Unit.NearbyFriendlyPlayers.Where(p => !p.Dead && !p.IsGhost && p.HealthPercent <= UltimateHealerSettings.Instance.Paladin.LightOfDawnHealth).Cast<WoWUnit>(), ClusterType.Cone, 30f) >= UltimateHealerSettings.Instance.Paladin.LightofDawnCount),
                               Spell.Heal("Word of Glory", ret => (WoWUnit)ret, ret => StyxWoW.Me.CurrentHolyPower == 3 && ((WoWUnit)ret).HealthPercent <= UltimateHealerSettings.Instance.Paladin.WordOfGloryHealth),
                               Spell.Heal("Holy Shock", ret => (WoWUnit)ret, ret => ((WoWUnit)ret).HealthPercent <= UltimateHealerSettings.Instance.Paladin.HolyShockHealth),
                               Spell.Heal("Holy Radiance", ret => Clusters.GetBestUnitForCluster(Unit.NearbyFriendlyPlayers.Cast<WoWUnit>(), ClusterType.Radius, 10f), ret => ((WoWUnit)ret).HealthPercent <= UltimateHealerSettings.Instance.Paladin.minHolyRadiance && Clusters.GetClusterCount((WoWUnit)ret,Unit.NearbyFriendlyPlayers.Where(p => !p.Dead && !p.IsGhost && p.HealthPercent <= UltimateHealerSettings.Instance.Paladin.minHolyRadiance).Cast<WoWUnit>(),ClusterType.Radius,10f) >= UltimateHealerSettings.Instance.Paladin.minHolyRadianceCount),
                               Spell.Heal("Divine Light", ret => (WoWUnit)ret, ret => ((WoWUnit)ret).HealthPercent <= UltimateHealerSettings.Instance.Paladin.minDivineLightIoL && StyxWoW.Me.ActiveAuras.ContainsKey("Infusion of Light")),
                               Spell.Heal("Flash of Light", ret => (WoWUnit)ret, ret => ((WoWUnit)ret).HealthPercent <= UltimateHealerSettings.Instance.Paladin.minDivineLightIoL && StyxWoW.Me.ActiveAuras.ContainsKey("Infusion of Light")),
                               Spell.Heal("Holy Light", ret => (WoWUnit)ret, ret => UltimateHealerSettings.Instance.Paladin.minDivineLightIoL == 0 && ((WoWUnit)ret).HealthPercent <= UltimateHealerSettings.Instance.Paladin.minHolyLight && StyxWoW.Me.ActiveAuras.ContainsKey("Infusion of Light")),
                               Spell.Heal("Flash of Light", ret => (WoWUnit)ret, ret => ((WoWUnit)ret).HealthPercent <= UltimateHealerSettings.Instance.Paladin.minFlashofLight),
                               Spell.Heal("Divine Light", ret => (WoWUnit)ret, ret => ((WoWUnit)ret).HealthPercent <= UltimateHealerSettings.Instance.Paladin.minDivineLight),
                               Spell.Heal("Holy Light", ret => (WoWUnit)ret, ret => ((WoWUnit)ret).HealthPercent <= UltimateHealerSettings.Instance.Paladin.minHolyLight),
                               new Decorator(
                                   ret => moveInRange,
                // Get in range
                                   Movement.CreateMoveToTargetBehavior(true, 35f, ret => (WoWUnit)ret))
                               )));
        }
        internal static Composite CreatePaladinUrgentDispel()
        {
            return new PrioritySelector();
        }
        internal static Composite CreatePaladinDispel() 
        {
            return new PrioritySelector();
        }
    }
}
